#include <vmm.h>
#include <types.h>
#include <host_syscall.h>
#include <proc.h>
#include <memlayout.h>
#include <pmm.h>
#include <mmu.h>

bool
copy_from_user(struct mm_struct *mm, void *dst, const void *src, size_t len, bool writable) {
    if (!user_mem_check(mm, (uintptr_t)src, len, writable)) {
        return 0;
    }
	if (mm == NULL) {
		memcpy(dst, src, len);
		return 1;
	}

	while (len > 0) {
		if (host_getvalue (current, (uintptr_t)src, NULL) < 0) {
			return 0;
		}

		size_t avail = ROUNDUP (src, PGSIZE) - src;
		if (PGOFF (src) == 0)
			avail += PGSIZE;
		if (avail > len)
			avail = len;
		
		pte_t *ptep = get_pte (mm->pgdir, (uintptr_t)src, 0);
		assert (ptep != NULL && (*ptep & PTE_P));
		uintptr_t addr = KERNBASE + PTE_ADDR (*ptep) + PGOFF (src);

		//cprintf ("copy from 0x%x to 0x%x, size = %d\n", addr, dst, avail);
		memcpy (dst, (void *)addr, avail);
		//cprintf ("copy end\n");

		len -= avail;
		dst += avail;
		src += avail;
	}
	
	/* if (host_getvalue (current, (uintptr_t)src, dst) < 0) */
	/* 	return 0; */
    return 1;
}

bool
copy_to_user(struct mm_struct *mm, void *dst, const void *src, size_t len) {
    if (!user_mem_check(mm, (uintptr_t)dst, len, 1)) {
        return 0;
    }
	if (mm == NULL) {
		memcpy(dst, src, len);
		return 1;
	}

	while (len > 0) {
		if (host_assign (current, (uintptr_t)dst, 0) < 0)
			return 0;
		
		size_t avail = ROUNDUP (dst, PGSIZE) - dst;
		if (PGOFF (dst) == 0)
			avail += PGSIZE;
		if (avail > len)
			avail = len;
		
		pte_t *ptep = get_pte (mm->pgdir, (uintptr_t)dst, 0);
		assert (ptep != NULL && (*ptep & PTE_P));
		uintptr_t addr = KERNBASE + PTE_ADDR (*ptep) + PGOFF (dst);

		//cprintf ("assign from 0x%x to 0x%x, size = %d\n", src, addr, avail);
		memcpy ((void *)addr, src, avail);
		//cprintf ("assign end\n");

		len -= avail;
		dst += avail;
		src += avail;
	}
	
	/* if (host_assign (current, (uintptr_t)dst, *(uintptr_t *)src) < 0) */
	/* 	return 0; */
	return 1;
}
